PHPでXMLをDOMとして扱う

10 5月

タイトルが適当なのかどうか分かりませんが、SimpleXML では扱いにくい処理があって、PHP で DOM を操作する方法を学んでみました。まず、欲しかった機能は、テキストで組み上げたXMLの要素を、DOMに組み込むというものです。

$xmltext = <<< end_of_quote
<?xml version="1.0" encoding="utf-8"?>
<root>
</root>
end_of_quote;
$xml = new DOMDocument();
//$xml->formatOutput = true;
$xml->loadXML($xmltext);
$root = $xml->getElementsByTagName("root")->item(0);
$f = $xml->createDocumentFragment();
$f->appendXML("<node>\n<a>hello</a>\n</node>");
$h = $xml->documentElement->appendChild($f);
$g = new DOMText("\n\n");
$root->appendChild($g);


echo $xml->saveXML(); 

改行を書き込んで整形しているのですが、他に方法がないものでしょうか。formatOutput が利きません。createDocumentFragment が何なのかが分かりません。この出力は下記。

<?xml version="1.0" encoding="utf-8"?>
<root>
<node>
<a>hello</a>
</node>
</root> 

もうひとつ必要となっている機能は、XML要素へのタグの追加です。先に加えた node タグに、新たにタグを追加します。

<?php
$xmltext = <<< end_of_quote
<?xml version="1.0" encoding="utf-8"?>
<root>
</root>
end_of_quote;
$xml = new DOMDocument();
//$xml->formatOutput = true;
$xml->loadXML($xmltext);
$root = $xml->getElementsByTagName("root")->item(0);
$f = $xml->createDocumentFragment();
$f->appendXML("<node>\n<a>hello</a>\n</node>");
$h = $xml->documentElement->appendChild($f);
$g = new DOMText("\n\n");
$root->appendChild($g);
$newnode = new DOMElement('b');
$h->appendChild($newnode);
$newnode->appendChild(new DOMText('hello'));
$h->appendChild(new DOMText("\n"));
echo $xml->saveXML();
?>

この出力は下記。

<?xml version="1.0" encoding="utf-8"?>
<root>
<node>
<a>hello</a>
<b>hello</b>
</node>
</root> 

 

以下、もう少し続けます。子要素を取得して、その内容を読み取ってみました。改行なども子要素となります。if文を書いて、改行などを拾わないようにしています。

<?php
$xmltext = <<< end_of_quote
<?xml version="1.0" encoding="utf-8"?>
<root>
<node>
a_hello
<node>b_hello</node>
</node>
<node>
c_hello
</node>
</root>
end_of_quote;

$xml = new DOMDocument();
$xml->loadXML($xmltext);
$root = $xml->getElementsByTagName("root")->item(0);
$alist = $root->childNodes;

foreach ($alist as $n) {
     if (trim($n->nodeValue)) {
          echo trim($n->nodeValue)."\n";
     }
}
?> 

この出力が下記。

a_hello
b_hello
c_hello

直接の子要素(孫でない)のみを読み取りたいのですが、やり方がわからない。

次に、子要素の削除です。入れ子になった node タグから、外側のタグだけ残します。内側に node タグを持つかどうかを調査して、持っていれば削除しています。

<?php
$xmltext = <<< end_of_quote
<?xml version="1.0" encoding="utf-8"?>
<root>
<node>
a_hello
<node>b_hello</node>
</node>
<node>
c_hello
</node>
</root>
end_of_quote;

$xml = new DOMDocument();
$xml->loadXML($xmltext);
$root = $xml->getElementsByTagName("root")->item(0);
$alist = $root->childNodes;

foreach ($alist as $n) {
     if ($n->hasChildNodes()) {
          $targetnode = $n->getElementsByTagName("node")->item(0);
          if ($targetnode) {
               $n->removeChild($targetnode);
          }
     }
}

echo $xml->saveXML();
?> 

出力は下記。

<?xml version="1.0" encoding="utf-8"?>
<root>
<node>
a_hello
</node>
<node>
c_hello
</node>
</root>